﻿//========================================================= 
/**@file H002CmdDriver.h
 * @brief H002 Android下驱动
 * 
 * @date 2016-04-26   17:15:16
 * @author Zhyioo 
 * @version 1.0
 */
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_H002JNICMDDRIVER_H_
#define _LIBZHOUYB_H002JNICMDDRIVER_H_
//--------------------------------------------------------- 
#include "../module/ComplexCmdInstaller.h"

#include "../module/ComICCardCmdDriver.h"
#include "../module/SdtApiCmdDriver.h"
#include "../module/IDCardCmdDriver.h"
#include "../module/MagneticCmdDriver.h"
#include "../module/LC_CmdDriver.h"
#include "../module/PBOC_CmdDriver.h"
#include "../module/DevPBOC_CmdDriver.h"
#include "../module/DevReader_CmdDriver.h"
#include "../module/ApplePayCmdDriver.h"
#include "../module/VisaPayCmdDriver.h"
#include "../module/SSC_CmdDriver.h"

#include "H002MagCmdDriver.h"
#include "H002PinCmdDriver.h"
#include "H002PinExCmdDriver.h"
#include "H002CardDetectorCmdDriver.h"
//--------------------------------------------------------- 
namespace zhou_yb {
namespace application {
namespace driver {
//--------------------------------------------------------- 
/// H002驱动
class H002Installer : public ComplexCmdInstaller
{
public:
    H002Installer() : ComplexCmdInstaller() {}
    H002Installer(CommandRunner& runner) : ComplexCmdInstaller(runner) {}
    /**
     * @brief 注册新的扩展口
     * @date 2017-04-20 21:50
     * 
     * @param [in] gateName 需要注册的扩展口命令名称
     * @param [in] gateCmd 扩展口指令
     * @param [in] devId [default:NULL] 底层设备所在模块(默认为主模块)
     */
    CommandSetter NewGate(const char* gateName, const char* gateCmd, const char* devId = NULL)
    {
        CommandSetter setter;
        if(_is_empty_or_null(gateName) || _is_empty_or_null(gateCmd) || _runner.IsNull())
            return setter;

        CommandSetter devSetter(*_runner);
        if(!_is_empty_or_null(devId))
        {
            Ref<CommandCollection> pDevCollection = _runner->Item(devId);
            if(pDevCollection.IsNull())
            {
                devSetter.Set(*pDevCollection);
            }
        }
        setter.Set(*_runner);
        StringArguments arg;
        arg.Put("Send", gateCmd);
        setter.New(gateName).Bind(devSetter.Cut("IsOpen"))
            .Bind(devSetter.Cut("Write"), arg);
        return setter;
    }
    /**
     * @brief 注册新的IInteractiveTrans接口设备(默认选择最后的IInteractiveTrans)
     * @date 2017-04-20 21:51
     * 
     * @param [in] devId 需要注册的设备ID
     */
    template<class T>
    CommandSetter InstallDEV(const char* devId)
    {
        if(_runner.IsNull() || _is_empty_or_null(devId))
            return CommandSetter();

        CommandSetter devSetter = _runner->template New<T>(devId);
        const char DEV_BIND_CMD[] = "Write;Read;IsOpen;Close;SetTimeoutMS;IInteractiveTrans";
        CommandSetter setter(_runner);
        setter.New(DEV_BIND_CMD);
        setter.New("DEV.IInteractiveTrans;DEV.Write;DEV.Read");

        // DEV.Open时自动选择设备
        string scriptName = "Script.";
        scriptName += devId;
        scriptName += ".OpenBindCMD";

        Ref<CommandScriptActuator> devScript = NewScriptCMD(devId);
        _BindCMD(devScript, devId, "", DEV_BIND_CMD);
        _BindCMD(devScript, devId, "DEV", "IInteractiveTrans;Write;Read");

        devScript->Run(devSetter.LookUp("IBaseDevice"))
            .ToArg().Run(_runner->Registe("Select_IBaseDevice"))
            .Clear(true, true)
            .Run(_runner->LookUp("IInteractiveTrans"))
            .ToArg().Run(_runner->Registe("Select_IInteractiveTrans"));
        setter.Registe(devId, devSetter.Cut("Open")).Bind(devScript->Script(scriptName.c_str()));
        return devSetter;
    }
    /**
     * @brief 装载H002支持的所有模块
     * @param [in] devId [default:NULL] 底层通信的设备的模块名,默认为主模块
     * @warning 该模块必须由外部装载,内部依赖 devId 进行配置
     *
     * @param [in] isMagInPin [default:true] 磁条模块是否由密码键盘控制(涉及到转口)
     *
     * @date 20161101 08:49
     */
    void Install(const char* devId = NULL, bool isMagInPin = true)
    {
        if(_runner.IsNull())
            return;

        CommandSetter devSetter(*_runner);
        const char DEV_ID[] = "";
        Ref<ComplexCommand> complexCmd = _runner->Registe("IInteractiveTrans");
        if(!_is_empty_or_null(devId))
        {
            Ref<CommandCollection> pDevCollection = _runner->Item(devId);
            if(!pDevCollection.IsNull())
            {
                devSetter.Set(*pDevCollection);
                complexCmd->Clear();
                complexCmd->Bind(devSetter.LookUp("IInteractiveTrans"));
            }
        }
        else
        {
            devId = DEV_ID;
        }

        CommandSetter setter = (*_runner);
        string icGate = "1B 24 49";
        string idGate = "1B 24 53";
        string magGate = "1B 24 41";
        string pinGate = "1B 24 4B";
        string finGate = "1B 24 46";
        string prtGate = "1B 24 50";

        const char SEND_KEY[] = "Send";
        const char ICC_GATE[] = "ICC_GATE";
        const char MAG_GATE[] = "MAG_GATE";
        const char IDC_GATE[] = "IDC_GATE";
        const char PIN_GATE[] = "PIN_GATE";
        const char PRINT_GATE[] = "PRINT_GATE";
        const char FINGER_GATE[] = "FINGER_GATE";

        // 扩展口 
        CommandSetter isOpenSetter = devSetter.Cut("IsOpen");
        CommandSetter writeSetter = devSetter.Cut("Write");
        StringArguments arg;
        string& gateCmd = arg.Put(SEND_KEY, "");
        gateCmd = icGate;
        setter.New(ICC_GATE).Bind(isOpenSetter).Bind(writeSetter, arg);
        gateCmd = magGate;
        setter.New(MAG_GATE).Bind(isOpenSetter).Bind(writeSetter, arg);
        gateCmd = idGate;
        setter.New(IDC_GATE).Bind(isOpenSetter).Bind(writeSetter, arg);
        gateCmd = pinGate;
        setter.New(PIN_GATE).Bind(isOpenSetter).Bind(writeSetter, arg);
        gateCmd = prtGate;
        setter.New(PRINT_GATE).Bind(isOpenSetter).Bind(writeSetter, arg);
        gateCmd = finGate;
        setter.New(FINGER_GATE).Bind(isOpenSetter).Bind(writeSetter, arg);
        /* 注册功能命令 */
        // 卡状态
        CommandInstaller::RegisteNew<H002CardDetectorCmdDriver>(*_runner, "Card")
            .PrefixBind(isOpenSetter);
        // H002
        CommandInstaller::RegisteNew<LC_CmdDriver>(*_runner, "LC")
            .Except("LC.SwitchToACK").PrefixBind(setter.Cut(ICC_GATE));
        // H002上的磁条
        CommandInstaller::RegisteNew<H002MagCmdDriver>(*_runner, "MAG")
            .PrefixBind(setter.Cut(isMagInPin ? PIN_GATE : MAG_GATE));
        // 磁条
        CommandInstaller::RegisteNew<MagneticCmdDriver>(*_runner, "Magnetic")
            .PrefixBind(setter.Cut(MAG_GATE));
        // IC卡
        CommandInstaller::RegisteNew<ComICCardCmdDriver>(*_runner, "IC")
            .PrefixBind(setter.Cut(ICC_GATE));
        // PBOC
        CommandInstaller::RegisteNew<PBOC_CmdDriver>(*_runner, "PBOC")
            .PrefixBind(setter.Cut(ICC_GATE));
        // 密码键盘
        CommandInstaller::RegisteNew<H002PinCmdDriver>(*_runner, "PIN")
            .PrefixBind(setter.Cut(PIN_GATE));
        // 密码键盘公私钥部分
        CommandInstaller::RegisteNew<H002PinExCmdDriver>(*_runner, "PINEX")
            .PrefixBind(setter.Cut(PIN_GATE));
        // SDTAPI
        CommandInstaller::RegisteNew<SdtApiCmdDriver>(*_runner, "SDTAPI")
            .PrefixBind(setter.Cut(IDC_GATE));
        // 身份证
        CommandInstaller::RegisteNew<IDCardCmdDriver>(*_runner, "ID")
            .PrefixBind(setter.Cut(IDC_GATE));
        // Dev.PBOC
        CommandInstaller::RegisteNew<DevPBOC_CmdDriver>(*_runner, "DevPBOC")
            .PrefixBind(setter.Cut(ICC_GATE));
        // Dev.Reader
        CommandInstaller::RegisteNew<DevReader_CmdDriver>(*_runner, "DevReader")
            .PrefixBind(setter.Cut(ICC_GATE));
        // ApplePay
        CommandInstaller::RegisteNew<ApplePayCmdDriver>(*_runner, "ApplePay")
            .PrefixBind(setter.Cut(ICC_GATE));
        // VisaPay
        CommandInstaller::RegisteNew<VisaPayCmdDriver>(*_runner, "VisaPay")
            .PrefixBind(setter.Cut(ICC_GATE));
        // SSC
        CommandInstaller::RegisteNew<SSC_CmdDriver>(*_runner, "SSC")
            .PrefixBind(setter.Cut(ICC_GATE));
        
        const char SELECT_DEVICE[] = "SelectDevice";
        // 创建硬件层 Select_IBaseDevice 接口
        Ref<ComplexCommand> selectCmd = _runner->Registe("Select_IBaseDevice");
        selectCmd->Bind(_runner->Get("LC").LookUp(SELECT_DEVICE), ComplexCommand::RunOnAlways);

        // 创建应用层 Select_IInteractiveTrans 接口
        selectCmd = _runner->Registe("Select_IInteractiveTrans");
        selectCmd->Bind(_runner->Get("Card").LookUp(SELECT_DEVICE), ComplexCommand::RunOnAlways);
        selectCmd->Bind(_runner->Get("IC").LookUp(SELECT_DEVICE), ComplexCommand::RunOnAlways);
        selectCmd->Bind(_runner->Get("SDTAPI").LookUp(SELECT_DEVICE), ComplexCommand::RunOnAlways);
        selectCmd->Bind(_runner->Get("Magnetic").LookUp(SELECT_DEVICE), ComplexCommand::RunOnAlways);
        selectCmd->Bind(_runner->Get("MAG").LookUp(SELECT_DEVICE), ComplexCommand::RunOnAlways);
        selectCmd->Bind(_runner->Get("PIN").LookUp(SELECT_DEVICE), ComplexCommand::RunOnAlways);
        selectCmd->Bind(_runner->Get("PINEX").LookUp(SELECT_DEVICE), ComplexCommand::RunOnAlways);
        selectCmd->Bind(_runner->Get("DevPBOC").LookUp(SELECT_DEVICE), ComplexCommand::RunOnAlways);
        selectCmd->Bind(_runner->Get("DevReader").LookUp(SELECT_DEVICE), ComplexCommand::RunOnAlways);

        // 创建 Select_ITransceiveTrans 接口
        selectCmd = _runner->Registe("Select_ITransceiveTrans");
        selectCmd->Bind(_runner->Get("PBOC").LookUp(SELECT_DEVICE), ComplexCommand::RunOnAlways);
        selectCmd->Bind(_runner->Get("ApplePay").LookUp(SELECT_DEVICE), ComplexCommand::RunOnAlways);
        selectCmd->Bind(_runner->Get("VisaPay").LookUp(SELECT_DEVICE), ComplexCommand::RunOnAlways);
        selectCmd->Bind(_runner->Get("SSC").LookUp(SELECT_DEVICE), ComplexCommand::RunOnAlways);

        // 在卡片上电和激活后自动的适配当前已激活的IC卡
        StringArguments bindArg;
        Ref<CommandScriptActuator> bindCmd = NewScriptCMD("PBOC");
        complexCmd = _runner->Get("IC").LookUp("ITransceiveTrans");
        _runner->Registe(complexCmd);
        bindCmd->Run(complexCmd);
        bindCmd->ToArg().Run(selectCmd);
        setter.Cut("IC.WaitForCard;IC.ScanForCardUID;IC.ActiveSLOT").Bind(bindCmd->Script("AutoSelectIC"));

        // 创建 DevPBOC.GetInformation 命令(硬件加速读取PBOC信息,功能同 PBOC.GetInformation)
        bindCmd = NewScriptCMD("DevPBOC");
        bindCmd->Import().Run(_runner->Get("PBOC").LookUp("SelectAid"));
        bindCmd->ToArg().Run(_runner->Get("PBOC").LookUp("GPO"));
        bindCmd->ToArg().Import(true).Run(_runner->Get("PBOC").LookUp("FLAGtoTAG")).Export();
        Ref<CommandScriptActuator> readScriptCmd = NewScriptCMD("DevPBOC");
        bindArg.Clear();
        bindArg.Put("Name", "App");
        bindArg.Put("Mode", "Replace");
        readScriptCmd->Import().Run(_runner->Get("DevPBOC").LookUp("ReadTAG"))
            .ToArg().Run(_runner->Get("PBOC").LookUp("SetTLV"), bindArg, ComplexCommand::BindImport);
        Ref<ComplexCommand> readGpoToken = _runner->Registe("ReadGpoTokenTAG");
        readGpoToken->Bind(readScriptCmd->ScriptCmd());
        readGpoToken->Bind(_runner->Get("PBOC").LookUp("ReadTAG"), ComplexCommand::RunOnFailed);
        bindCmd->Run(readGpoToken);
        setter.New("DevPBOC.GetInformation").Bind(setter.Cut(ICC_GATE))
            .Bind(bindCmd->Script("HardwarePBOC"));

        // LC模块设置ACK切换功能
        Ref<ComplexCommand> lcAckCmd = _runner->LookUp("LC.SwitchToACK");
        lcAckCmd->Clear();
        bindArg.Clear();
        bindArg.Put("Timeout", "200");
        bindCmd = NewScriptCMD("LC");
        complexCmd = _runner->LookUp("SetTimeoutMS");
        bindCmd->Run(complexCmd, bindArg).ToArg().Import(true)
            .Run(_runner->Get("LC").LookUp("SwitchToACK"))
            .Run(complexCmd, ComplexCommand::RunOnAlways);
        lcAckCmd->Bind(bindCmd->ScriptCmd("AutoSwitchToACK"));

        complexCmd = _runner->Get("LC").LookUp("IInteractiveTrans");
        _BindCMD(bindCmd, "LC", "", "Write;Read;IInteractiveTrans");
        bindCmd = NewScriptCMD("LC");
        bindCmd->Run(complexCmd).ToArg().Run(_runner->LookUp("Select_IInteractiveTrans"));
        lcAckCmd->Bind(bindCmd->ScriptCmd("AutoSelectACK"));

        // 错误信息
        _runner->LastErr().New("H002")
            .New("ITransceiveTrans")
            .Add("PBOC").Add("ApplePay").Add("VisaPay").Add("SSC")
            .End().Select("IC")
            .New("IInteractiveTrans")
            .Add("Card").Add("LC").Add("Magnetic").Add("MAG").Add("PIN").Add("PINEX")
            .New("ISdtApi")
            .Add("ID")
            .End()
            .Select("SDTAPI")
            .Add("DevPBOC").Add("DevReader")
            .End()
            .New("IBaseDevice")
            .Add(devId)
            .End();

        CommandRunnerActuator actuator(*_runner);
        // 适配 IInteractiveTrans 接口 
        actuator.Run("IInteractiveTrans", true).Run("Select_IInteractiveTrans").Set("LC").Run(SELECT_DEVICE).Reset();
        // 适配 IInterrptBehavior 接口
        actuator.Set("Unit").Run("IInterrupter", true).All().Run("SetInterrupter").Reset();
        // 适配 IWltDecoder 接口
        actuator.Set("WLT").Run("IWltDecoder", true).Set("ID").Run("SetWltDecoder").Reset();
        // 适配 ISdtApi 接口
        actuator.Set("SDTAPI").Run("ISdtApi", true).Set("ID").Run(SELECT_DEVICE).Reset();
        // 初始化二代证
        actuator.Set("SDTAPI").Arg("Timeout", 800).Call("SetDelayTimeout").Reset();
        // 卡片识别器
        actuator.Set("Card").Arg("Contact", icGate).Arg("Contactless", icGate)
            .Arg("MAG", isMagInPin ? pinGate : magGate).Arg("IDC", idGate).Run("SetGate").Reset();

        // 重置错误信息
        actuator.All().Run("ResetError").Reset();
        _runner->ResetErr();
    }
    /**
     * @brief 注册新的子模块
     * @date 2017-03-14 10:10
     * 
     * @param [in] id 新的模块名称
     * @param [in] gateName [default:NULL] 模块连接的逻辑扩展口
     */
    template<class T>
    CommandSetter InstallNEW(const char* id, const char* gateName = NULL)
    {
        if(_runner.IsNull())
            return CommandSetter();

        Ref<T> refT;
        CommandSetter newSetter = CommandInstaller::RegisteNew<T>(*_runner, id, &refT);

        // 反射 T 支持的适配类型
        const char SELECT_DEVICE[] = "SelectDevice";
        CommandRunnerActuator actuator(*_runner);
        CommandLastErrGetter& errGetter = (*_runner).LastErr();
        Ref<ComplexCommand> complexCmd = refT->LookUp(SELECT_DEVICE);
        if(!complexCmd.IsNull())
        {
            StringArguments rlt;
            complexCmd->OnCommand(rlt, rlt);

            IStringArguments::EnumeratorType enumer = rlt.GetEnumerator();
            while(enumer.MoveNext())
            {
                string& key = enumer.Current().Key;
                string& val = enumer.Current().Value;
                if(!StringConvert::Compare(key.c_str(), "Adapter"))
                    continue;
                errGetter.MoveTo(val.c_str()).Add(id);
                actuator.Reset();
                actuator.Set("").Run(val.c_str(), true).Set(id).Run(SELECT_DEVICE).Reset();

                string selectName = "Select_";
                selectName += val;
                _runner->Registe(selectName.c_str())->Bind(refT->LookUp(SELECT_DEVICE), ComplexCommand::RunOnAlways);
            }
        }
        else
        {
            errGetter.MoveTo("H002").Add(id);
        }
        // 设置扩展口
        if(!_is_empty_or_null(gateName))
        {
            CommandSetter setter(*_runner);
            newSetter.PrefixBind(setter.Cut(gateName));
        }
        // 适配 IInterrptBehavior 接口
        actuator.Set("Unit").Run("IInterrupter", true).Add(id).Run("SetInterrupter").Reset();
        actuator.All().Run("ResetError").Reset();
        _runner->ResetErr();
        return newSetter;
    }
};
//--------------------------------------------------------- 
} // nemespace driver
} // namespace application
} // namespace zhou_yb
//--------------------------------------------------------- 
#endif // _LIBZHOUYB_H002JNICMDDRIVER_H_
//========================================================= 